package com.yixing.tech.entity.service.impl;

import org.apache.commons.lang3.StringUtils;
import com.yixing.tech.common.base.BusinessException;
import com.yixing.tech.common.base.ConditionsVO;
import com.yixing.tech.common.base.ErrorNotifyData;
import com.yixing.tech.common.enums.ErrCode;
import com.yixing.tech.common.enums.ValueRef;
import com.yixing.tech.entity.entity.RequestType;
import com.yixing.tech.entity.entity.attr.*;
import com.yixing.tech.entity.po.EntityData;
import com.yixing.tech.entity.service.EntityBaseService;
import com.yixing.tech.entity.utils.ExpressionUtil;
import com.yixing.tech.common.utils.CommonUtil;
import com.yixing.tech.common.utils.DataUtil;
import com.yixing.tech.common.vo.s3.DepartmentVO;
import com.yixing.tech.common.vo.s3.DictVO;
import com.yixing.tech.common.vo.s3.RoleVO;
import com.yixing.tech.common.vo.s3.UserVO;
import com.yixing.tech.common.vo.s5.EntitySchema;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.modelmapper.TypeToken;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.AddFieldsOperation;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.aggregation.ProjectionOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yixing tech
 * @description
 * @date 2024/5/31 10:13:48
 */
@Service
@Slf4j
public class ObjProcessor {

    @Resource
    MongoTemplate mongoTemplate;

    @Resource
    @Lazy
    private EntityBaseService entityBaseService;


    /**
     * 反向引用赋值
     *
     * @param map
     * @param attrs
     */
    @Async
    public void putBackRefValue(Map<String, Object> map, List<EntitySchema.AttrVO> attrs, boolean isUpdate) throws BusinessException {
        for (EntitySchema.AttrVO attrVO : attrs) {
            List<EntitySchema.AttrVO.BackReference> backRefs = attrVO.getBackReferences();
            if (!CommonUtil.listIsBlank(backRefs)) {
                putRefValue(attrs, backRefs, map, attrVO.getCode(), isUpdate);
            }
            if (AttrType.build(attrVO.getType()) instanceof ObjArray) {
                List<EntitySchema.AttrVO> subAttrVOs = DataUtil.o2o(attrVO.getReference(), new TypeToken<List<EntitySchema.AttrVO>>() {
                }.getType());
                Object value = map.get(attrVO.getCode());
                if (ObjectUtils.isEmpty(value)) return;
                List<Map<String, Object>> subMaps = (List<Map<String, Object>>) value;
                if (CommonUtil.listIsBlank(subMaps)) return;
                for (Map<String, Object> m : subMaps) {
                    for (EntitySchema.AttrVO subAttr : subAttrVOs) {
                        backRefs = subAttr.getBackReferences();
                        if (!CommonUtil.listIsBlank(backRefs)) {
                            putRefValue(subAttrVOs, backRefs, m, subAttr.getCode(), isUpdate);
                        }
                    }
                }
            }
        }
    }

    /**
     * 回写引用值
     *
     * @param attrs
     * @return
     */
    public void putRefValue(List<EntitySchema.AttrVO> attrs, List<EntitySchema.AttrVO.BackReference> backReferences, Map<String, Object> map, String code, boolean isUpdate) throws BusinessException {
        for (EntitySchema.AttrVO.BackReference m : backReferences) {
            EntityData en = putRefValue(attrs, m, map, code, isUpdate);
            if (en != null) {
                entityBaseService.updateEntity(en.getObjCode(), en);
            }
        }
    }

    /**
     * 回写引用值
     *
     * @param attrs
     * @return
     */
    private EntityData putRefValue(List<EntitySchema.AttrVO> attrs, EntitySchema.AttrVO.BackReference backReference, Map<String, Object> map, String code, boolean isUpdate) throws BusinessException {
        String refStr = backReference.getReference();
        if (!refStr.startsWith("$")) return null;
        String[] codes = refStr.split("\\.");
        if (codes.length < 2) return null;
        String refObjCode = codes[0].substring(1);
        EntitySchema.AttrVO refAttr = getAttr(refObjCode, attrs);
        AttrType refType = AttrType.build(refAttr.getType());
        if (refType instanceof Obj) {
            Object refValue = map.get(refObjCode);
            if (null == refValue) return null;
            Object value = null;
            if (null != code) {
                value = map.get(code);
                if (value == null) return null;
            }
            String rf = refAttr.getRelationalField();
            String templateId = refAttr.getReference().toString();
            ObjectId entityId;
            if (refValue instanceof Map) {
                entityId = new ObjectId(((Map) refValue).get("id").toString());
            } else {
                entityId = new ObjectId(ObjectUtils.isEmpty(rf) ? refValue.toString() : mongoTemplate.findOne(
                        Query.query(Criteria.where(rf).is(refValue.toString())),
                        Document.class, getTableName(templateId)).getString("id"));
            }

            String formulas = backReference.getFormulas();
            if (!StringUtils.isEmpty(formulas)) {
                //配置了公式的回写，不支持修改
                if (isUpdate) return null;
                Document document = mongoTemplate.findById(entityId, Document.class, getTableName(templateId));
                Object oldValue = document.get(codes[1]);
                Map temp = new HashMap(map);
                temp.put(refStr.substring(1), oldValue);
                value = ExpressionUtil.evaluate(temp, formulas);
            }
            EntityData entity = new EntityData();
            entity.put("id", entityId);
            entity.put(codes[1], value);
            entity.setObjCode(templateId);
            return entity;
        } else if (refType instanceof ArraySubObj) {
            //todo 回写子表单里实体数据
        }
        return null;
    }

    public String getTableName(String templateId) {


        return "entity_" + templateId;
    }

    /**
     * 获取引用值
     *
     * @param attrs
     * @param refTarget
     * @return
     */
    public Object getRefValue(List<EntitySchema.AttrVO> attrs, String[] refTarget, Map<String, Object> map, Map<String, Object> tempMap, AttrType currentAttrType) throws BusinessException {
        String refObjCode = refTarget[0].substring(1);
        EntitySchema.AttrVO refAttr = getAttr(refObjCode, attrs);
        AttrType refType = AttrType.build(refAttr.getType());
        if (refType instanceof Obj || refType instanceof Dict || refType instanceof User || refType instanceof Department
                || refType instanceof Signature || refType instanceof ObjArray || refType instanceof ArraySubObj) {
            Object refValue = map.get(refObjCode);
            if (ObjectUtils.isEmpty(refValue)) return null;
            Object valueObj;
            if (refType instanceof ObjArray || refType instanceof ArraySubObj) {
                valueObj = refValue;
            } else {
                String entityId;
                if (refValue instanceof Document) {
                    Document refValueDoc = (Document) refValue;
                    Object entityIdObj = refValueDoc.get("id");
                    if (entityIdObj == null) return null;
                    entityId = entityIdObj.toString();
                } else if (refValue instanceof List) {
                    List refValueDoc = (List) refValue;
                    Object entityIdObj = refValueDoc.get(0);
                    if (entityIdObj == null) return null;
                    entityId = entityIdObj.toString();
                } else entityId = refValue.toString();
                Object targetValue = tempMap.get(refObjCode);
                if (targetValue == null) {
                    if (refType instanceof Obj) {
                        String templateId = refAttr.getReference().toString();
                        String rf = refAttr.getRelationalField();
                        if (ObjectUtils.isEmpty(rf))
                            targetValue = mongoTemplate.findById(new ObjectId(entityId), Document.class, getTableName(templateId));
                        else {
                            targetValue = mongoTemplate.findOne(
                                    Query.query(Criteria.where(rf).is(entityId)),
                                    Document.class, getTableName(templateId));
                        }
                    } else if (refType instanceof Dict) {
                        String rf = refAttr.getRelationalField();
                        if (ObjectUtils.isEmpty(rf))
                            targetValue = mongoTemplate.findById(new ObjectId(entityId), Document.class, "dict");
                        else {
                            String templateId = refAttr.getReference().toString();
                            targetValue = mongoTemplate.findOne(
                                    Query.query(Criteria.where(rf).is(entityId).and("parentId").is(templateId)),
                                    Document.class, "dict");
                        }

                    } else if (refType instanceof User || refType instanceof Signature) {
                        targetValue = mongoTemplate.findById(new ObjectId(entityId), Document.class, "user");
                    } else if (refType instanceof Department) {
                        targetValue = mongoTemplate.findById(new ObjectId(entityId), Document.class, "department");
                    }
                    tempMap.put(refObjCode, targetValue);
                }
                if (null == targetValue) return targetValue;
                valueObj = targetValue;
            }

            for (int i = 1; i < refTarget.length; i++) {
                if (null == valueObj) return valueObj;
                String code = refTarget[i];
                if ("id".equals(code) || "_id".equals(code)) {
                    Object temp = ((Document) valueObj).get("id");
                    if (temp == null) temp = ((Document) valueObj).get("_id");
                    valueObj = temp.toString();
                } else {
                    valueObj = ((Document) valueObj).get(code);
                }

            }

            if (valueObj instanceof Document) {
                if (currentAttrType instanceof Dict || currentAttrType instanceof User || currentAttrType instanceof Obj || currentAttrType instanceof Role ||
                        currentAttrType instanceof UserGroup || currentAttrType instanceof ObjTemplate || currentAttrType instanceof Department) {
                    Object temp = ((Document) valueObj).get("id");
                    if (temp == null) temp = ((Document) valueObj).get("_id");
                    valueObj = temp.toString();
                } else if (currentAttrType instanceof SingleText) {
                    valueObj = ((Document) valueObj).get("name").toString();
                }
            }
            return valueObj;
        } else {
            return map.get(refObjCode);
        }
    }

    /**
     * 值处理
     *
     * @param map
     * @param attrs
     */
    public String parserValue(Map<String, Object> map, List<EntitySchema.AttrVO> attrs, boolean isUpdate, boolean isImport, Map<String, String> dictTemp, Map<String, Object> oldMap) throws BusinessException {
        return parserValue(map, attrs, isUpdate, isImport, dictTemp, oldMap, true);
    }

    /**
     * 值处理
     *
     * @param map
     * @param attrs
     */
    public String parserValue(Map<String, Object> map, List<EntitySchema.AttrVO> attrs, boolean isUpdate, boolean isImport, Map<String, String> dictTemp, Map<String, Object> oldMap, boolean hasCheck) throws BusinessException {

        //拆分字段，用于批量新增
        String splitCode = null;

        Map<String, Object> tempMap = new HashMap<>(5);
        label:
        for (EntitySchema.AttrVO attrVO : attrs) {
            String attrCode = attrVO.getCode();
            Object ref = attrVO.getReference();
            AttrType attrType = AttrType.build(attrVO.getType());
            Object value = map.get(attrCode);

            if (attrType instanceof InsertEvent || attrType instanceof UpdateEvent || attrType instanceof CustomOp || attrType instanceof ObjList) {
                map.remove(attrCode);
                continue;
            }
            //赋值自动编号
            if (!isUpdate && attrType instanceof ID) {
                ID id = (ID) attrType;
                if (!map.containsKey(attrCode))
                    value = id.getValue(attrVO.getReference());
            }

            //开关量默认false
            if (!isUpdate && attrType instanceof SwitchText) {
                if (CommonUtil.stringIsBlank(value)) value = false;
            }

            //数字量默认0
            if (!isUpdate && attrType instanceof DigitalText) {
                if (CommonUtil.stringIsBlank(value)) value = 0;
            }


            if (CommonUtil.stringIsBlank(value)) continue;
            /**
             * 导入时，处理特殊类型
             */
            if (isImport) {
                if (attrType instanceof Dict) {
                    String relationalField = attrVO.getRelationalField();
                    if (ObjectUtils.isEmpty(relationalField)) {
                        String dictName = value.toString();
                        if (dictTemp == null) dictTemp = new HashMap<>();
                        String key = CommonUtil.stringIsBlank(ref) ? dictName : (ref.toString() + dictName);
                        if (dictTemp.containsKey(key))
                            value = dictTemp.get(key);
                        else {
                            Criteria criteria = Criteria.where("name").is(dictName);
                            if (!CommonUtil.stringIsBlank(ref)) {
                                criteria.and("parentId").is(ref.toString());
                            }
                            Query query = Query.query(criteria);
                            DictVO dictVO = mongoTemplate.findOne(query, DictVO.class, "dict");
                            if (dictVO != null) {
                                value = dictVO.getId();
                                dictTemp.put(key, dictVO.getId());
                            } else {
                            }
                        }
                    }
                } else if (attrType instanceof SingleText) {
                    String valueStr = value.toString();
                    //认为是时间串
                    if (valueStr.contains("GMT+08:00") && valueStr.length() >= 16) {
                        try {
                            value = valueStr.substring(11, 16);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

            if (attrType instanceof Obj || attrType instanceof Dict) {
                String relationalF = attrVO.getRelationalField();
                if (value instanceof List) {

                } else {
                    if (ObjectUtils.isEmpty(relationalF)) {
                        Document document = new Document();
                        document.put("id", new ObjectId(value instanceof Map ? map.get("id").toString() : value.toString()));
                        value = document;
                    } else if (value instanceof Map) {
                        value = ((Map) value).get(relationalF);
                    }
                }
            } else if ((attrType instanceof DictArray) || (attrType instanceof MultiObject)) {
                List list = (List) value;
                String relationalF = attrVO.getRelationalField();
                if (ObjectUtils.isEmpty(relationalF) && !ObjectUtils.isEmpty(list)) {
                    value = list.stream().map(m -> new ObjectId(m.toString())).collect(Collectors.toList());
                }
            } else if (attrType instanceof Signature) {
                Document document = new Document();
                Object user = map.get(isUpdate ? "updateId" : "createId");
                if (!CommonUtil.stringIsBlank(user)) {
                    document.put("id", new ObjectId(user.toString()));
                    value = document;
                }

            } else if (attrType instanceof ObjArray) {
                if (!ObjectUtils.isEmpty(value) && hasCheck) {
                    List<EntitySchema.AttrVO> subAttrVOs = DataUtil.o2o(ref, new TypeToken<List<EntitySchema.AttrVO>>() {
                    }.getType());
                    List<Map<String, Object>> subMaps = (List<Map<String, Object>>) value;
                    for (int i = 0; i < subMaps.size(); i++) {
                        Map<String, Object> m = subMaps.get(i);
                        for (EntitySchema.AttrVO subAttr : subAttrVOs) {
                            String subAttrCode = subAttr.getCode();
                            EntitySchema.AttrVO.Constraint constraint = subAttr.getConstraint();
                            if (constraint != null) {
                                checkValue(subAttrVOs, constraint, m, subAttrCode, i, attrCode, map, attrs);
                            }
                        }
                    }
                }
            } else value = attrType.in(value, attrVO);
            map.put(attrCode, value);
        }


        for (EntitySchema.AttrVO attrVO : attrs) {
            String attrCode = attrVO.getCode();
            Object idleValue = attrVO.getIdleValue();
            Object ref = attrVO.getReference();
            AttrType attrType = AttrType.build(attrVO.getType());
            Object value = map.get(attrCode);
            String valueFormat = attrVO.getValueFormat();
            //赋值默认值
            if (!isUpdate && null != idleValue && idleValue.toString().length() > 0) {
                if (ObjectUtils.isEmpty(value)) {
                    if ((idleValue instanceof String) && idleValue.toString().startsWith("$")) {
                        //变量
                        String refStr = idleValue.toString();
                        String[] codes = refStr.split("\\.");
                        value = getRefValue(attrs, codes, map, tempMap, attrType);
                    } else {
                        //常量
                        value = idleValue;

                    }
                }

            }

            //赋值引用值
            if (!CommonUtil.stringIsBlank(ref)) {
                if (attrType instanceof SubObj) continue;
                String refStr = ref.toString();
                if (refStr.startsWith("$")) {
                    String[] codes = refStr.split("\\.");
                    value = getRefValue(attrs, codes, map, tempMap, attrType);
                }
            }

            if (attrType instanceof ObjTemplate) {
                if (!ObjectUtils.isEmpty(value) && !(value instanceof Map)) {
                    Document document = new Document();
                    document.put("id", new ObjectId(value.toString()));
                    value = document;
                }
            } else if (attrType instanceof Obj || attrType instanceof Dict) {
                String relationalField = attrVO.getRelationalField();
                if (value instanceof List) {
                    //拆分字段批量新增
                    List list = (List) value;
                    if (ObjectUtils.isEmpty(relationalField) && !ObjectUtils.isEmpty(list)) {
                        value = list.stream().map(m -> {
                            Document doc = new Document();
                            doc.put("id", new ObjectId(m.toString()));
                            return doc;
                        }).collect(Collectors.toList());
                    }
                    splitCode = attrCode;
                } else {
                    if (ObjectUtils.isEmpty(relationalField)) {
                        if (!ObjectUtils.isEmpty(value) && !(value instanceof Map)) {
                            Document document = new Document();
                            try {
                                document.put("id", new ObjectId(value.toString()));
                                value = document;
                            } catch (Exception e) {
                                throw new BusinessException(-1, "关联对象id格式错误");
                            }
                        }
                    }
                }
            }

            //赋值公式
            if (!CommonUtil.stringIsBlank(ref) && attrType instanceof FormulasText) {
                if (isUpdate) {
                    for (String key : map.keySet()) {
                        Object v = map.get(key);
                        if (v != null) {
                            if (v instanceof Map) {
                                Map temp = (Map) v;
                                if (temp.isEmpty()) continue;
                            }
                            oldMap.put(key, v);
                        }
                    }
                    value = "bool".equals(valueFormat) ? ExpressionUtil.evaluateCondition(oldMap, ref.toString()) : formulas(ref.toString(), oldMap);
                } else {
                    value = "bool".equals(valueFormat) ? ExpressionUtil.evaluateCondition(map, ref.toString()) : formulas(ref.toString(), map);
                }
            }
            //格式化
            if (!StringUtils.isEmpty(valueFormat)) {
                if (valueFormat.startsWith("%")) {
                    value = String.format(attrVO.getValueFormat(), value);
                } else if (valueFormat.startsWith("T")) {
                    String valueFormatStr = valueFormat.substring(1);
                    Date date = value instanceof Date ? (Date) value : new Date(Long.parseLong(value.toString()));
                    SimpleDateFormat sdf = new SimpleDateFormat(valueFormatStr);
                    try {
                        Date newDate = sdf.parse(sdf.format(date));
                        value = newDate;
                    } catch (ParseException e) {
                        throw new RuntimeException(e);
                    }
                }
            }

            //赋值关联值
            List<EntitySchema.AttrVO.BackReference> backReferences = attrVO.getBackReferences();
            if (!ObjectUtils.isEmpty(backReferences)) {
                for (EntitySchema.AttrVO.BackReference b : backReferences) {
                    String refStr = b.getReference();
                    if (!refStr.startsWith("$")) continue;
                    String[] codes = refStr.split("\\.");
                    if (codes.length < 2) continue;
                    String refObjCode = codes[0].substring(1);
                    EntitySchema.AttrVO refAttr = getAttr(refObjCode, attrs);
                    AttrType refType = AttrType.build(refAttr.getType());
                    if (!(refType instanceof ObjArray)) continue;
                    Object refValue = map.get(refObjCode) != null ? map.get(refObjCode) : oldMap != null ? oldMap.get(refObjCode) : null;
                    if (null == refValue) return splitCode;
                    if (value == null) continue;
                    List<Map> refDocs = (List<Map>) refValue;
                    for (Map doc : refDocs) {
                        doc.put(codes[1], map.get(attrCode));
                    }
                }
            }
            map.put(attrCode, value);
            //check value
            if (hasCheck) {
                EntitySchema.AttrVO.Constraint constraint = attrVO.getConstraint();
                if (constraint != null) {
                    checkValue(attrs, constraint, map, attrCode, 0, null, map, attrs);
                }
            }
        }
        return splitCode;
    }

    /**
     * 约束提醒
     *
     * @param attrs
     * @return
     */
    public void checkValue(List<EntitySchema.AttrVO> attrs, EntitySchema.AttrVO.Constraint constraint, Map<String, Object> map,
                           String code, Integer index, String fCode, Map<String, Object> fmap, List<EntitySchema.AttrVO> fAttrs) throws BusinessException {
        Map temp = new HashMap(map);
        Object value = map.get(code);
        if (value == null) return;
        String formulas = constraint.getFormulas();
        if (StringUtils.isEmpty(formulas)) return;
        String refStr = constraint.getReference();
        if (!StringUtils.isEmpty(refStr)) {
            String[] refStrs = refStr.split(",");
            Map<String, Object> refObjTemp = new HashMap<>();
            for (String str : refStrs) {
                if (!str.startsWith("$")) continue;
                String[] codes = str.split("\\.");
                String refObjCode = codes[0].substring(1);
                Object document = refObjTemp.get(refObjCode);
                if (document == null) {
                    EntitySchema.AttrVO refAttr = getAttr(refObjCode, attrs);
                    Object refValue = map.get(refObjCode);
                    if (null == refValue) continue;
                    AttrType refType = AttrType.build(refAttr.getType());
                    if (refType instanceof Obj) {
                        ObjectId entityId;
                        if (refValue instanceof Map) {
                            entityId = new ObjectId(((Map) refValue).get("id").toString());
                        } else entityId = new ObjectId(refValue.toString());
                        String templateId = refAttr.getReference().toString();
                        document = mongoTemplate.findById(entityId, Document.class, getTableName(templateId));
                    } else if (refType instanceof ArraySubObj) {
                        String refRef = refAttr.getReference().toString();
                        String[] codes1 = refRef.split("\\.");
                        List refValue1 = (List) getRefValue(fAttrs, codes1, fmap, refObjTemp, new ObjArray());
                        int i = Integer.valueOf(refValue.toString());
                        if (CommonUtil.listIsBlank(refValue1) || refValue1.size() <= i)
                            throw new BusinessException(ErrCode.MISS_CONFIG);
                        document = refValue1.get(i);
                    } else {
                        document = refValue;
                    }
                    refObjTemp.put(refObjCode, document);
                }
                Object targetValue = codes.length > 1 ? ((Document) document).get(codes[1]) : document;
                temp.put(str.substring(1), targetValue);

            }
        }
        boolean isValid = ExpressionUtil.evaluateCondition(temp, formulas);
        if (!isValid) {
            ErrorNotifyData error = new ErrorNotifyData();
            if (fCode == null) {
                error.setAttrCode(code);
                error.setErrorDesc(constraint.getDesc());
            } else {
                error.setAttrCode(fCode);
                List<ErrorNotifyData> children = new ArrayList<>();
                ErrorNotifyData child = new ErrorNotifyData(index, code, constraint.getDesc(), null);
                children.add(child);
                error.setChildren(children);
            }
            throw new BusinessException(ErrCode.ERROR_NOTIFY, error);
        }

    }


    /**
     * 对象列表数据在属主对象上快捷新增
     *
     * @param parent
     * @param attrs
     * @throws BusinessException
     */
    public void fillObjList(EntityData savePre, EntityData saveAfter, List<EntitySchema.AttrVO> attrs) throws BusinessException {
        Optional<EntitySchema.AttrVO> objListAttr = attrs.stream().filter(f -> f.getType().equals("objList")).findFirst();
        if (!objListAttr.isPresent()) return;
        EntitySchema.AttrVO attrVO = objListAttr.get();
        String code = attrVO.getCode();
        List<Map> list = savePre.getList(code, Map.class);
        if (ObjectUtils.isEmpty(list)) return;
        Object reference = attrVO.getReference();
        Map refMap = (Map) reference;
        Object linkCode = refMap.get("parentCode");
        Object meteObjCode = refMap.get("meteObj");
        if (ObjectUtils.isEmpty(linkCode) || ObjectUtils.isEmpty(meteObjCode))
            throw new BusinessException(-1, "对象列表配置不正确");
        Object linkValue = saveAfter.get(linkCode);
        list.forEach(map -> {
            map.put(linkCode, linkValue);
            map.put("createId", savePre.get("createId"));
            map.put("createName", savePre.get("createName"));
            map.put("tenantId", savePre.get("tenantId"));
            map.put("departmentId", savePre.get("departmentId"));
        });
        entityBaseService.insetEntitys(meteObjCode.toString(), list, null);
    }

    /**
     * 字段过滤及填充
     *
     * @param operations
     * @param matchConfig
     * @throws BusinessException
     */
    public void projectAttr(List<AggregationOperation> operations, List<EntitySchema.AttrConfig> matchConfig, EntitySchema objVO, RequestType requestType) throws BusinessException {
        List<EntitySchema.AttrVO> attrs = objVO.getAttrs();
        if (matchConfig == null) matchConfig = new ArrayList<>();
        int size = matchConfig.size();
        String[] matchAttrs = new String[size];
        for (int i = size - 1; i >= 0; i--) {
            EntitySchema.AttrConfig config = matchConfig.get(i);
            String code = config.getCode();
            AttrType attrType = getAttrType(code, attrs);
            matchAttrs[i] = config.getCode();
            EntitySchema.AttrVO attr = getAttr(code, attrs);
            attrType.out(operations, attr, requestType);
        }
        String agentCode = objVO.getAgentAttrCode();
        if (!ObjectUtils.isEmpty(agentCode)) {
            AddFieldsOperation addFieldsOperation = Aggregation.addFields().addFieldWithValue("name", "$" + agentCode).build();
            operations.add(addFieldsOperation);
            matchAttrs = ArrayUtils.addAll(matchAttrs, "approvalInfo", "approvalStatus", "isDelete", "name");
        } else {
            matchAttrs = ArrayUtils.addAll(matchAttrs, "approvalInfo", "approvalStatus", "isDelete");
        }
        ProjectionOperation projectionOperation = Aggregation.project(matchAttrs);
        operations.add(projectionOperation);
    }

    /**
     * 字段过滤及填充
     *
     * @param operations
     * @param matchConfig
     * @throws BusinessException
     */
    public void projectAttr(List<AggregationOperation> operations, List<EntitySchema.AttrConfig> matchConfig, EntitySchema objVO) throws BusinessException {
        projectAttr(operations, matchConfig, objVO, RequestType.COMPLEX);
    }

    /**
     * 过滤条件兼容
     *
     * @param conditionsVO
     * @param attrs
     */
    public void parseConditions(ConditionsVO conditionsVO, List<EntitySchema.AttrVO> attrs) throws BusinessException {
        if (conditionsVO == null) return;
        List<ConditionsVO.Condition> list = conditionsVO.getConditions();
        if (list == null) return;
        for (ConditionsVO.Condition cond : list) {
            String key = cond.getKey();
            AttrType attrType = getAttrType(key, attrs);
            EntitySchema.AttrVO attr = getAttr(key, attrs);
            attrType.condition(cond, attr);
        }
    }

    /**
     * 融合只读字段权限
     *
     * @param templateId
     * @param matchConfig
     * @param userVO
     */
    public void fillNotReadAttrConfig(String templateId, List<EntitySchema.AttrConfig> matchConfig, UserVO userVO) {
        RoleVO roleVO = userVO == null ? null : DataUtil.mergeRole(userVO.getRole(), userVO.getSelfRole());
        if (roleVO == null || roleVO.getDataConfigs() == null || roleVO.getDataConfigs().get(templateId) == null)
            return;
        List<String> notReadAttrs = roleVO.getDataConfigs().get(templateId).getNotReadAttr();
        if (notReadAttrs == null) return;
        if (matchConfig == null) return;
        int size = matchConfig.size();
        for (int i = size - 1; i >= 0; i--) {
            EntitySchema.AttrConfig config = matchConfig.get(i);
            if (notReadAttrs.contains(config.getCode())) matchConfig.remove(i);
        }

    }

    /**
     * 融合查询权限
     */
    public void fillConditionConfig(String templateId, ConditionsVO conditionsVO, UserVO userVO) {
        List<ConditionsVO.Condition> conds = new ArrayList<>();
        List<ConditionsVO.Condition> conditions1 = conditionsVO.getConditions();
        if (!ObjectUtils.isEmpty(conditions1)) conds.addAll(conditions1);
        RoleVO roleVO = userVO == null ? null : DataUtil.mergeRole(userVO.getRole(), userVO.getSelfRole());
        if (roleVO != null && roleVO.getDataConfigs() != null && roleVO.getDataConfigs().get(templateId) != null) {
            List<ConditionsVO.Condition> conditions = roleVO.getDataConfigs().get(templateId).getConditions();
            if (!ObjectUtils.isEmpty(conditions)) {
                int size = conds.size();
                for (int i = size - 1; i >= 0; i--) {
                    ConditionsVO.Condition condition = conds.get(i);
                    if (conditions.stream().anyMatch(m -> m.getKey().equals(condition.getKey()))) conds.remove(i);
                }
                conds.addAll(conditions);
            }
        }
        for (ConditionsVO.Condition cond : conds) {
            if(cond.getValue() == null) {
                continue;
            }
            String value = cond.getValue().toString();
            if (ValueRef.$$self.name().equals(value)) {
                cond.setValue(userVO.getId());
            } else if (ValueRef.$$department.name().equals(value)) {
                cond.setValue(userVO.getDepartment() != null ? userVO.getDepartment().getId() : null);
            }
        }
        conditionsVO.setConditions(conds);

    }

    /**
     * 返回属性配置
     *
     * @param code
     * @param attrs
     * @return
     */
    public EntitySchema.AttrVO getAttr(String code, List<EntitySchema.AttrVO> attrs) {
        for (EntitySchema.AttrVO attrVO : attrs) {
            if (code.equals(attrVO.getCode())) {
                return attrVO;
            }
        }
        return new EntitySchema.AttrVO();
    }

    public AttrType getAttrType(String code, List<EntitySchema.AttrVO> attrs) {
        for (EntitySchema.AttrVO attrVO : attrs) {
            if (code.equals(attrVO.getCode())) {
                return AttrType.build(attrVO.getType());
            }
        }
        if ("createTime".equals(code) || "updateTime".equals(code)) return new TimeText();
        if ("createId".equals(code)) return new User();
        if ("departmentId".equals(code)) return new Department();

        return new SingleText();
    }

    public void  fillCreateUser(Map vo, UserVO userVO) {
        if (userVO != null) {
            vo.put("createId", userVO.getId());
            vo.put("createName", userVO.getName());
            vo.put("tenantId", userVO.getTenantId());
            DepartmentVO departmentVO = userVO.getDepartment();
            if (departmentVO != null)
                vo.put("departmentId", departmentVO.getId());
        }
        Date date = new Date();
        vo.put("createTime", date);
        vo.put("updateTime", date);
    }

    /**
     * 返回属性配置
     *
     * @param code
     * @param attrs
     * @return
     */
    public EntitySchema.AttrConfig getAttrConfig(String code, List<EntitySchema.AttrConfig> attrs) {
        if (attrs == null) return null;
        for (EntitySchema.AttrConfig attrVO : attrs) {
            if (code.equals(attrVO.getCode())) {
                return attrVO;
            }
        }
        return null;
    }

    /**
     * 公式计算
     *
     * @param ref
     * @param map
     * @return
     */
    public Object formulas(String ref, Map<String, Object> map) {
        try {
            return ExpressionUtil.evaluate(map, ref);
        } catch (BusinessException e) {
            e.printStackTrace();
            log.error(e.getMessage());
            return null;
        }
    }

}
